在前面的文章中我們跳過了一個部分,那就是指令在傳輸時要進行加密的方式。以連線遊戲來說,如果我們將玩家操作的指令明文的暴露出來的話,除了對安全性有部分影響之外,也很容易被外掛利用變成破壞遊戲平衡的問題之一。
如果是網站的話現在大多已經有 HTTPS 可以使用,但是採用 TCP Socket 連線的話就需要自己實作。
在 Unlight 裡面,連線的加密使用了一種叫做 SRP (Secure Remote Password) 的機制,單純看原理的話其實也不算複雜,不過背後有許多複雜的計算方式我們就不需要去深入瞭解。簡單說就是伺服器跟客戶端透過某種方式計算出叫做 Session Key 的加密金鑰,然後再傳送前先用把金鑰對資料做一次 XOR 的運算,收到時再做一次 XOR 運算就能取回原本的資訊。
我們可以在客戶端的 ULSocket 裡面(src/net/ULSocket.as
)看到發送資料時的處理
/**
* コマンドを送信
* @param data 送信するデータ
*/
public function send(data:ByteArray):void
{
var ba:ByteArray = new ByteArray();
// ...
writeShort (data.length);
writeBytes (cipher.encrypt(data));
// ...
}
我們會發現發送出的資料是透過 cipher
這個物件用 encrypt
方法處理過的資料,而不是明文的資料。
同樣的,在伺服器 ULServer 裡面(src/protocol/ulserver.rb
)也會發現相關的處理
def data2command(data)
# ...
while i < d_size
# ...
if data[i+len+2] == "\n"
d = @crypt.decrypt(data[i+2,len])
a << [d[0,2].unpack('n')[0], d[2..-1]]
end
# ...
end
a
end
當找出封包的內容區段後,會使用 @crypt
物件做 #decrypt
的處理,再將指令的內容回傳用於後面處理指令解析的地方。
因此我們要來討論這中間的加密跟解密是如何運作,而 SRP 在 Unlight 裡面又能夠做些什麼呢?
SRP 聽起來像是一個很新的名詞,不過從出現的時間看起來似乎是個有點歷史的東西。實際上我們會在維基百科的條目上發現,像是 OpenSSL 也都是 SRP 的實作,而像是 1Password 等服務,也都是有使用 SRP 的。
我的個人部落格是弦而時習之平常會把自己發現的一些新技巧紀錄在上面,也歡迎大家來逛逛。